package com.frogs.ucenter.v1.service.impl;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.frogs.framework.util.PageList;
import com.frogs.framework.util.StringUtil;
import com.frogs.system.util.ApplicablePlatformEnum;
import com.frogs.system.util.RechargeBalanceStatusEnum;
import com.frogs.system.util.SmsPartnerEnum;
import com.frogs.system.util.UserAccountInfoStatusEnum;
import com.frogs.system.util.UserMessageStatusEnum;
import com.frogs.system.web.api.request.Request;
import com.frogs.system.web.api.response.Response;
import com.frogs.system.web.api.response.Response.ApiResultEnum;
import com.frogs.system.web.exception.ServiceOperationException;
import com.frogs.ucenter.component.SmsHelper;
import com.frogs.ucenter.dao.UserAccountInfoDao;
import com.frogs.ucenter.dao.UserRechargeBalanceDao;
import com.frogs.ucenter.dao.UserRechargeConsumeBlockingDao;
import com.frogs.ucenter.dao.UserRechargeConsumeRecordDao;
import com.frogs.ucenter.entity.UserAccountInfo;
import com.frogs.ucenter.entity.UserMessageSmsVerifyCode;
import com.frogs.ucenter.entity.UserRechargeBalance;
import com.frogs.ucenter.entity.UserRechargeConsumeBlocking;
import com.frogs.ucenter.entity.UserRechargeConsumeRecord;
import com.frogs.ucenter.util.Constants;
import com.frogs.ucenter.v1.request.SmsSendConsumeCodeRequest;
import com.frogs.ucenter.v1.request.SmsVerifyConsumeCodeRequest;
import com.frogs.ucenter.v1.request.UserBalanceConsumeRequest;
import com.frogs.ucenter.v1.request.UserRechargeBalanceBlockingRequest;
import com.frogs.ucenter.v1.request.UserRechargeBalanceReleaseRequest;
import com.frogs.ucenter.v1.request.UserRechargeBalanceUnfreezeRequest;
import com.frogs.ucenter.v1.request.UserRechargeConsumeListByDateRequest;
import com.frogs.ucenter.v1.request.UserRechargeConsumeRecordListRequest;
import com.frogs.ucenter.v1.response.AddResponse;
import com.frogs.ucenter.v1.response.DefaultResponse;
import com.frogs.ucenter.v1.response.PageListResponse;
import com.frogs.ucenter.v1.response.UpdateResponse;
import com.frogs.ucenter.v1.service.UserRechargeConsumeRecordService;
import com.frogs.ucenter.v1.util.ApiConstants;

@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class) 
@Service(ApiConstants.VERSION+"userRechargeConsumeRecordService")
public class UserRechargeConsumeRecordServiceImpl extends UserRechargeStrategyBaseServiceImpl implements UserRechargeConsumeRecordService {
	
	private static final Logger log = LoggerFactory.getLogger(UserRechargeConsumeRecordServiceImpl.class);
	
	@Resource
	private UserRechargeConsumeRecordDao userRechargeConsumeRecordDao;
	@Resource
	private UserRechargeBalanceDao userRechargeBalanceDao;
	@Resource
	private UserAccountInfoDao userAccountInfoDao;
	@Resource
	private UserRechargeConsumeBlockingDao blockingDao;
	@Resource
	private SmsHelper smsHelper;
	
	/**
	 * 余额消费
	 */
	@Override
	public Response balanceConsume(Request request) throws Exception {
		DefaultResponse response = new DefaultResponse();
		try {
			UserBalanceConsumeRequest balanceConsumeRequest = (UserBalanceConsumeRequest) request;
			Integer userId = balanceConsumeRequest.getUserId();
			String code = balanceConsumeRequest.getCode();
			BigDecimal consumeMoney = balanceConsumeRequest.getConsumeMoney();
			UserAccountInfo userAccountInfo = userAccountInfoDao.selectById(userId);
			if (userAccountInfo == null) {
				throw new ServiceOperationException("该用户不存在");
			}
			if (userAccountInfo.getIsPhoneValid() == UserAccountInfoStatusEnum.AVAILABILITY_NO.getId() 
					|| StringUtil.isEmpty(userAccountInfo.getPhone())) {
				throw new ServiceOperationException("该用户未绑定手机号");
			}
			
			String phone = userAccountInfo.getPhone();
			if(verifySms(phone, code, userId, UserMessageStatusEnum.VERIFY.getId())) {
				String orderId = balanceConsumeRequest.getOrderId();
				BigDecimal blockingMoney = showBlockingMoney(orderId);
				if(blockingMoney.compareTo(new BigDecimal("0.00")) == 1) {
					//先解冻现有的冻结金额
					mergeBlockingBalance(userId, orderId, blockingMoney,  RechargeBalanceStatusEnum.UNFREEZE.getId());
				}
				
				balanceConsumeVerify(consumeMoney, userId);
				// 消费送积分,商城做此操作
				//givePointByConsume(userId, consumeMoney, UserIntegralRecordEnum.ORDER_EXCHANGE.getId());
				insertConsumeRecord(balanceConsumeRequest);
			}
		} catch (Exception e) {
			log.error("func[{}] request[{}] exception[{}] desc[fail]",
					new Object[] { this.getClass().getName() +"."+Thread.currentThread().getStackTrace()[1].getMethodName(),
						request,Arrays.deepToString(e.getStackTrace()) });
			throw new ServiceOperationException("请求处理失败：" + e.getMessage());
		}
		return response;
	}
	
	/**
	 * 插入消费记录
	 * 
	 * @param balanceConsumeRequest
	 */
	private void insertConsumeRecord(UserBalanceConsumeRequest balanceConsumeRequest) {
		UserRechargeConsumeRecord userRechargeConsumeRecord = new UserRechargeConsumeRecord();
		userRechargeConsumeRecord.setUserId(balanceConsumeRequest.getUserId());
		userRechargeConsumeRecord.setConsumeMoney(balanceConsumeRequest.getConsumeMoney());
		userRechargeConsumeRecord.setConsumeContent(balanceConsumeRequest.getConsumeContent());
		userRechargeConsumeRecord.setOrderId(balanceConsumeRequest.getOrderId());
		userRechargeConsumeRecordDao.insert(userRechargeConsumeRecord);
	}
	
	/**
	 * 余额消费检测
	 * 
	 * @param consumeMoney
	 * @param userId
	 */
	private void balanceConsumeVerify(BigDecimal consumeMoney, Integer userId) throws Exception {
		UserRechargeBalance userRechargeBalance = userRechargeBalanceDao.selectById(userId);
		if(null != userRechargeBalance) {
			BigDecimal balance = userRechargeBalance.getBalance();
			String encryptBalance = userRechargeBalance.getEncryptBalance();
			if (StringUtil.md5(userId + balance.toString(), Constants.ENCRYPT_BALABCE_KEY).equals(encryptBalance)) {
				if (balance.compareTo(consumeMoney) == -1) {
					throw new ServiceOperationException("余额不足");
				}
				userRechargeBalance.setBalance(balance.subtract(consumeMoney));
				userRechargeBalance.setEncryptBalance(StringUtil.md5(userId + balance.subtract(consumeMoney).toString(), Constants.ENCRYPT_BALABCE_KEY));
				userRechargeBalance.setUpdateDate(new Date());
				userRechargeBalanceDao.update(userRechargeBalance);
			} else {
				log.error("func[balanceConsumeVerify] userId[" + userId + "] balance[" + balance + "] desc[旧的余额有误]");
				throw new ServiceOperationException("旧的余额有误");
			}
		} else {
			log.error("func[balanceConsumeVerify] userId[" + userId + "] desc[该账户没余额]");
			throw new ServiceOperationException("该账户没余额");
		}
	}
	
	/**
	 * 恢复余额检测
	 * 
	 * @param consumeMoney
	 * @param userId
	 */
	private void restorebalance(BigDecimal consumeMoney, Integer userId) throws Exception {
		UserRechargeBalance userRechargeBalance = userRechargeBalanceDao.selectById(userId);
		if (null != userRechargeBalance) {
			BigDecimal balance = userRechargeBalance.getBalance();
			String encryptBalance = userRechargeBalance.getEncryptBalance();
			if (StringUtil.md5(userId + balance.toString(), Constants.ENCRYPT_BALABCE_KEY).equals(encryptBalance)) {
				userRechargeBalance.setBalance(balance.add(consumeMoney));
				userRechargeBalance.setEncryptBalance(StringUtil.md5(userId + balance.add(consumeMoney).toString(), Constants.ENCRYPT_BALABCE_KEY));
				userRechargeBalance.setUpdateDate(new Date());
				userRechargeBalanceDao.update(userRechargeBalance);
			} else {
				log.error("func[restorebalance] userId[" + userId + "] balance[" + balance + "] desc[旧的余额有误]");
				throw new ServiceOperationException("旧的余额有误");
			}
		} else {
			log.error("func[restorebalance] userId[" + userId + "] desc[该账户没余额]");
			throw new ServiceOperationException("该账户没余额");
		}
	}
	
	/**
	 * 发送消费验证码
	 */
	@Override
	public Response sendConsumeCode(Request request) throws Exception {
		DefaultResponse response = new DefaultResponse();
		try {
			SmsSendConsumeCodeRequest sendConsumeCodeRequest = (SmsSendConsumeCodeRequest) request;
			Integer userId = sendConsumeCodeRequest.getUserId();
			String phone = sendConsumeCodeRequest.getPhone();
			Integer applicablePlatformId = sendConsumeCodeRequest.getApplicablePlatformId();
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("eqId", userId);
			params.put("eqPhone", phone);
			params.put("eqIsPhoneValid", UserAccountInfoStatusEnum.AVAILABILITY_YES.getId());
			int count = userAccountInfoDao.selectCountByMap(params);
			if (count < 1) {
				throw new ServiceOperationException("该用户未绑定该手机号码");
			}
			Response result = smsHelper.sendVerify(phone, UserMessageSmsVerifyCode.SendOperationEnum.PAY.getValue(), 60*10, applicablePlatformId, SmsPartnerEnum.BAI_FEN.getCode());
			if (result.getCode() == ApiResultEnum.FAIL.getId()) {
				throw new ServiceOperationException(result.getTip());
			}
		} catch (Exception e) {
			log.error("func[{}] request[{}] exception[{}] desc[fail]",
					new Object[] { this.getClass().getName() +"."+Thread.currentThread().getStackTrace()[1].getMethodName(),
						request,Arrays.deepToString(e.getStackTrace()) });
			throw new ServiceOperationException("请求处理失败：" + e.getMessage());
		}
		return response;
	}
	
	/**
	 * 校验消费验证码
	 */
	@Override
	public Response verifyConsumeCode(Request request) throws Exception {
		SmsVerifyConsumeCodeRequest verifyRequest = (SmsVerifyConsumeCodeRequest) request;
		DefaultResponse response = new DefaultResponse();
		try {
			boolean result = this.verifySms(verifyRequest.getPhone(), verifyRequest.getCode(), verifyRequest.getUserId(), UserMessageStatusEnum.UNVERIFY.getId());
			if(result) {
				response.setTip("校验成功");
			} else {
				throw new ServiceOperationException("验证码校验失败");
			}
		} catch (Exception e) {
			log.error("func[{}] request[{}] exception[{}] desc[fail]",
					new Object[] { this.getClass().getName() +"."+Thread.currentThread().getStackTrace()[1].getMethodName(),
						request,Arrays.deepToString(e.getStackTrace()) });
			throw new ServiceOperationException("请求处理失败：" + e.getMessage());
		}
		return response;
	}
	
	/**
	 * 校验短信
	 * 
	 * @param phone
	 * @param messageContent
	 */
	private boolean verifySms(String phone, String code, Integer userId, int status) throws Exception  {
		Response response = smsHelper.checkVerify(phone, code, UserMessageSmsVerifyCode.SendOperationEnum.PAY.getValue(), 
				ApplicablePlatformEnum.WEB.getId(), status);
		if (response.getCode() == ApiResultEnum.FAIL.getId()) {
			throw new ServiceOperationException(response.getTip());
		}
		return true;
	}

	/**
	 * 余额消费记录列表
	 */
	@Override
	public Response listConsume(Request request) throws Exception {
		UserRechargeConsumeRecordListRequest listRequest = (UserRechargeConsumeRecordListRequest)request;
		PageListResponse<UserRechargeConsumeRecord> listResponse = new PageListResponse<UserRechargeConsumeRecord>(); 
		try {
			PageList<UserRechargeConsumeRecord> lists = this.getUserRechargeConsumeRecordList(listRequest.getUserId(), listRequest.getPageNo(), listRequest.getPageSize());
			listResponse.setList(lists);
			listResponse.setPageTurn(lists.getPageTurn());
		} catch (Exception e) {
			log.error("func[{}] request[{}] exception[{}] desc[fail]",
					new Object[] { this.getClass().getName() +"."+Thread.currentThread().getStackTrace()[1].getMethodName(),
						request,Arrays.deepToString(e.getStackTrace()) });
			throw new ServiceOperationException("请求处理失败：" + e.getMessage());
		}
		return listResponse;
	}

	private PageList<UserRechargeConsumeRecord> getUserRechargeConsumeRecordList(int userId , int pageNo , int pageSize){
		Map<String, Object> params = new HashMap<String,Object>();
		params.put("eqUserId", userId);
		params.put("orderByClause", "consume_time desc");
		PageList<UserRechargeConsumeRecord> lists = userRechargeConsumeRecordDao.selectAllRecordByMap(params, pageNo, pageSize);
		return lists;
	}
	
	/**
	 * 冻结余额
	 */
	@Override
	public Response blockingRechargeBalance(Request request) throws Exception {
		UserRechargeBalanceBlockingRequest blockingRequest = (UserRechargeBalanceBlockingRequest) request;
		AddResponse<UserRechargeConsumeBlocking> blockingResponse = new AddResponse<UserRechargeConsumeBlocking>(); 
		try {
			
			String code = blockingRequest.getCode();
			Integer userId = blockingRequest.getUserId();
			UserAccountInfo userAccountInfo = userAccountInfoDao.selectById(userId);
			if (userAccountInfo == null) {
				throw new ServiceOperationException("该用户不存在");
			}
			if (userAccountInfo.getIsPhoneValid() == UserAccountInfoStatusEnum.AVAILABILITY_NO.getId() 
					|| StringUtil.isEmpty(userAccountInfo.getPhone())) {
				throw new ServiceOperationException("该用户未绑定手机号");
			}
			String phone = userAccountInfo.getPhone();
			if(!verifySms(phone, code, userId, UserMessageStatusEnum.VERIFY.getId())){
				throw new ServiceOperationException("验证码有误");
			}
			UserRechargeConsumeBlocking consumeBlocking = mergeBlockingBalance(userId, blockingRequest.getOrderId(), blockingRequest.getConsumeMoney(), RechargeBalanceStatusEnum.BLOCKING.getId());
			blockingResponse.setInfo(consumeBlocking);
			blockingResponse.setTip("成功冻结余额" + blockingRequest.getConsumeMoney() + "元");
		} catch (Exception e) {
			log.error("func[{}] request[{}] exception[{}] desc[fail]",
					new Object[] { this.getClass().getName() +"."+Thread.currentThread().getStackTrace()[1].getMethodName(),
						request,Arrays.deepToString(e.getStackTrace()) });
			throw new ServiceOperationException("请求处理失败：" + e.getMessage());
		}
		
		return blockingResponse;
	}
	
	/**
	 * 解冻金额
	 */
	@Override
	public Response unfreezeRechargeBalance(Request request) throws Exception {
		UserRechargeBalanceUnfreezeRequest unfreezeRequest = (UserRechargeBalanceUnfreezeRequest) request;
		UpdateResponse<UserRechargeConsumeBlocking> unfreezeResponse = new UpdateResponse<UserRechargeConsumeBlocking>();
		try {
			UserAccountInfo userAccountInfo = userAccountInfoDao.selectById(unfreezeRequest.getUserId());
			if (userAccountInfo == null) {
				throw new ServiceOperationException("该用户不存在");
			}
			
			UserRechargeConsumeBlocking consumeBlocking = mergeBlockingBalance(unfreezeRequest.getUserId(), unfreezeRequest.getOrderId(),unfreezeRequest.getConsumeMoney(),  RechargeBalanceStatusEnum.UNFREEZE.getId());
			unfreezeResponse.setInfo(consumeBlocking);
			unfreezeResponse.setTip("成功解冻金额" + unfreezeRequest.getConsumeMoney() + "元");
			
		} catch (Exception e) {
			log.error("func[{}] request[{}] exception[{}] desc[fail]",
					new Object[] { this.getClass().getName() +"."+Thread.currentThread().getStackTrace()[1].getMethodName(),
						request,Arrays.deepToString(e.getStackTrace()) });
			throw new ServiceOperationException("请求处理失败：" + e.getMessage());
		}
		return unfreezeResponse;
	}
	
	/**
	 * 清除冻结金额
	 */
	@Override
	public Response releaseBlockingBalance(Request request) throws Exception {
		UserRechargeBalanceReleaseRequest releaseRequest = (UserRechargeBalanceReleaseRequest) request;
		UpdateResponse<UserRechargeConsumeBlocking> releaseResponse = new UpdateResponse<UserRechargeConsumeBlocking>();
		try {
			UserAccountInfo userAccountInfo = userAccountInfoDao.selectById(releaseRequest.getUserId());
			if (userAccountInfo == null) {
				throw new ServiceOperationException("该用户不存在");
			}
			
			UserRechargeConsumeBlocking consumeBlocking = mergeBlockingBalance(releaseRequest.getUserId(), releaseRequest.getOrderId(),releaseRequest.getConsumeMoney(),  RechargeBalanceStatusEnum.RELEASE.getId());
			
//			givePointByConsume(releaseRequest.getUserId(), releaseRequest.getConsumeMoney(), UserIntegralRecordEnum.ORDER_EXCHANGE.getId());
			insertConsumeRecord(releaseRequest);
			
			releaseResponse.setInfo(consumeBlocking);
			releaseResponse.setTip("成功消费冻结金额" + releaseRequest.getConsumeMoney() + "元");
			
		} catch (Exception e) {
			log.error("func[{}] request[{}] exception[{}] desc[fail]",
					new Object[] { this.getClass().getName() +"."+Thread.currentThread().getStackTrace()[1].getMethodName(),
						request,Arrays.deepToString(e.getStackTrace()) });
			throw new ServiceOperationException("请求处理失败：" + e.getMessage());
		}
		return releaseResponse;
	}
	
	/**
	 * 修改冻结记录
	 * @param userId
	 * @param orderId
	 * @param consumeMoney
	 * @return
	 * @throws Exception
	 */
	private UserRechargeConsumeBlocking mergeBlockingBalance(Integer userId, String orderId, BigDecimal consumeMoney, int status) throws Exception {
		Map<String, Object> params = new HashMap<String,Object>();
		params.put("eqOrderId", orderId);
		params.put("eqUserId", userId);
		PageList<UserRechargeConsumeBlocking> list = blockingDao.selectByMap(params, false);
		UserRechargeConsumeBlocking consumeBlocking = null;
		boolean exist = true;
		boolean needUpdate = true;
		BigDecimal tmpBalance = new BigDecimal("0.00");
		if(list.size() > 0) {
			consumeBlocking = list.get(0);
			if(consumeBlocking.getUserId().compareTo(userId) != 0) {
				throw new Exception("无权限操作!");
			}
			if(status == consumeBlocking.getStatus()) {
				if(consumeMoney.compareTo(consumeBlocking.getAmount()) == 0) {
					needUpdate = false;
				} else {
					tmpBalance = consumeBlocking.getAmount();
				}
			}
		} else {
			consumeBlocking = new UserRechargeConsumeBlocking();
			exist = false;
		}
		
		if(exist) {
			if(RechargeBalanceStatusEnum.RELEASE.getId() == status 
					&& consumeBlocking.getStatus() != RechargeBalanceStatusEnum.BLOCKING.getId()) {
				throw new ServiceOperationException("不存在冻结余额，请确认！");
			}
			if(RechargeBalanceStatusEnum.UNFREEZE.getId() == status 
					&& consumeBlocking.getStatus() != RechargeBalanceStatusEnum.BLOCKING.getId()) {
				throw new ServiceOperationException("不存在冻结余额，请确认！");
			}
		}
		
		if(needUpdate) {
			consumeBlocking.setAmount(consumeMoney);
			consumeBlocking.setCreateTime(new Date());
			consumeBlocking.setOrderId(orderId);
			consumeBlocking.setUserId(userId);
			consumeBlocking.setStatus(status);
			
			if(!exist && RechargeBalanceStatusEnum.BLOCKING.getId() == status) {
				blockingDao.insert(consumeBlocking);
			} else if(!exist && RechargeBalanceStatusEnum.BLOCKING.getId() != status) {
				throw new Exception("该订单没有冻结记录!");
			} else if(exist){
				if(RechargeBalanceStatusEnum.BLOCKING.getId() == status) {
					restorebalance(tmpBalance, userId);
				}
				blockingDao.update(consumeBlocking);
			}
			
			if(RechargeBalanceStatusEnum.BLOCKING.getId() == status) {
				//从余额减去相应金额
				balanceConsumeVerify(consumeMoney, userId);
			} else if(RechargeBalanceStatusEnum.UNFREEZE.getId() == status) {
				//增加相应金额
				restorebalance(consumeMoney, userId);
			}
		}
		return consumeBlocking;
	}

	/* 
	 * 根据日期获取消费记录，提供给财务调用
	 */
	@Override
	public Response listConsumeByDate(Request request) throws Exception {
		PageListResponse<UserRechargeConsumeRecord> response = new PageListResponse<UserRechargeConsumeRecord>();
		try {
			UserRechargeConsumeListByDateRequest userRechargeConsumeListByDateRequest = (UserRechargeConsumeListByDateRequest) request;
			Date startDate = userRechargeConsumeListByDateRequest.getStartDate();
			Date endDate = userRechargeConsumeListByDateRequest.getEndDate();
			Integer pageNo = userRechargeConsumeListByDateRequest.getPageNo();
			Integer pageSize = userRechargeConsumeListByDateRequest.getPageSize();
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("gtConsumeTime", startDate);
			params.put("ltConsumeTime", endDate);
			params.put("orderByClause", "consume_time asc");
			PageList<UserRechargeConsumeRecord> list = userRechargeConsumeRecordDao.selectByMap(params, pageNo, pageSize, true);
			response.setList(list);
			response.setPageTurn(list.getPageTurn());
		} catch (Exception e) {
			log.error("func[{}] request[{}] exception[{}] desc[fail]",
					new Object[] { this.getClass().getName() +"."+Thread.currentThread().getStackTrace()[1].getMethodName(),
						request,Arrays.deepToString(e.getStackTrace()) });
			throw new ServiceOperationException("请求处理失败：" + e.getMessage());
		}
		return response;
	}
	
}